package com.test.zk;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.List;

public class ZkUtil {
    private ZooKeeper zk;//连接zookeeper的connection
    private static final String address = "10.9.20.152";
    private static final int sessionTimeout = 30000;

    public void createConnection() {
        try {
            zk = new ZooKeeper(address, sessionTimeout, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    System.out.println("已经触发了" + event.getType() + "事件！");
                    //1、获取事件状态
                    Event.KeeperState state = event.getState();
                    //2、获取事件类型
                    Event.EventType type = event.getType();
                    //获取节点地址
                    String path = event.getPath();
                    //3、判断是否连接
                    if (Event.KeeperState.SyncConnected == state) {
                        //4、判断类型
                        if (Event.EventType.None == type) {
                            System.out.println("###zookeeper建立连接成功###");
                        } else if (Event.EventType.NodeCreated == type) {
                            System.out.println("###Watcher监听的对应数据节点被创建###, 当前新增节点：" + path);
                        } else if (Event.EventType.NodeDataChanged == type) {
                            System.out.println("###Watcher监听的对应数据节点的数据内容发生变更###, 当前节点：" + path + "，被修改...");
                        } else if (Event.EventType.NodeChildrenChanged == type) {
                            System.out.println("###Wather监听的对应数据节点的子节点列表发生变更###, 当前子节点：" + path + "，被修改...");
                        } else if (Event.EventType.NodeDeleted == type) {
                            System.out.println("###Watcher监听的对应数据节点被删除###, 当前节点：" + path + "，被删除...");
                        }
                    }
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean createNode(String path, String data) {
        try {
            this.exist(path, true);//先判断节点是否存在
            /**
             * acl:权限列表
             提供默认的权限OPEN_ACL_UNSAFE、CREATOR_ALL_ACL、READ_ACL_UNSAFE
             OPEN_ACL_UNSAFE：完全开放
             CREATOR_ALL_ACL：创建该znode的连接拥有所有权限
             READ_ACL_UNSAFE：所有的客户端都可读

             */
            /**
             * PERSISTENT 持久化节点
             * PERSISTENT_SEQUENTIAL 顺序自动编号持久化节点，这种节点会根据当前已存在的节点数自动加 1
             * EPHEMERAL 临时节点， 客户端session超时这类节点就会被自动删除
             * EPHEMERAL_SEQUENTIAL 临时自动编号节点
             */
            zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println("###新增节点信息path:" + path + " data:" + data);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 判断指定节点是否存在
     *
     * @param path
     * @param needWatch
     * @return
     */
    public Stat exist(String path, boolean needWatch) {
        try {
            return this.zk.exists(path, needWatch);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public void close() {
        try {
            if (zk != null) {
                zk.close();
                System.out.println("###zookeeper服务已关闭");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public byte[] getNodeData(String path, boolean needWatch, Stat stat) {
        try {
            byte[] data = zk.getData(path, needWatch, stat);
            return data;
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询子节点
     *
     * @param path
     * @param needWatch
     * @return
     */
    public List<String> getChildren(String path, boolean needWatch) {
        try {
            return zk.getChildren(path, needWatch);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    public boolean updateNode(String path, String data) {
        try {
            this.exist(path, true);
            //zk的数据版本是从0开始计数的。如果客户端传入的是-1，则表示zk服务器需要基于最新的数据进行更新。如果对zk的数据节点的更新操作没有原子性要求则可以使用-1.
            //version参数指定要更新的数据的版本, 如果version和真实的版本不同, 更新操作将失败. 指定version为-1则忽略版本检查
            zk.setData(path, data.getBytes(), -1);
            System.out.println("###修改节点信息path:" + path + " data:" + data);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean deleteNode(String path) {
        try {
            this.exist(path, true);
            zk.delete(path, -1);
            System.out.println("###删除节点信息path:" + path);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static void main(String[] args) {
        ZkUtil test = new ZkUtil();
        test.createConnection();//连接成功
        //创建节点,根目录是/
        //test.createNode("/test/node1","11111");
        // byte[] data = test.getNodeData("/test/node1", false, null);
        //演示临时节点
        //test.createNode("/temp","now");
        // test.deleteNode("/test/node1/t2");
        byte[] data = test.getNodeData("/dubbo/com.test.restruant.service.DishTableService/providers/dubbo%3A%2F%2F10.9.20.159%3A20882%2Fcom.test.restruant.service.DishTableService%3Fanyhost%3Dtrue%26application%3Dservice-provider%26dubbo%3D2.6.2%26generic%3Dfalse%26interface%3Dcom.test.restruant.service.DishTableService%26methods%3DinsertSelective%2CinsertList%2CgetTableList%2Cupdate%2Cinsert%26pid%3D4996%26revision%3D1.0-SNAPSHOT%26side%3Dprovider%26timeout%3D30000%26timestamp%3D1557027663564", false, null);
        //持久带序号的节点
        //test.createNode("/test/node1/t2", "now");
        List<String> children = test.getChildren("/dubbo/com.test.restruant.service.DishTableService/providers/dubbo%3A%2F%2F10.9.20.159%3A20882%2Fcom.test.restruant.service.DishTableService%3Fanyhost%3Dtrue%26application%3Dservice-provider%26dubbo%3D2.6.2%26generic%3Dfalse%26interface%3Dcom.test.restruant.service.DishTableService%26methods%3DinsertSelective%2CinsertList%2CgetTableList%2Cupdate%2Cinsert%26pid%3D4996%26revision%3D1.0-SNAPSHOT%26side%3Dprovider%26timeout%3D30000%26timestamp%3D1557027663564", false);
        for (String child : children) {
            System.out.println(child);
        }
        System.out.println(new String(data));
        test.close();
    }
}
